package modelController.sessionController;

import entities.Edgeamongknowledge;
import entities.Knowledge;
import entities.Leadpoint;
import entities.Learningresource;
import entities.Majorsubject;
import entities.Praise;
import entities.Reexamination;
import entities.Student;
import entities.Subject;
import entities.TeacherAdmin;
import entities.User;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.model.DataModel;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import jxl.*;
import jxl.read.biff.BiffException;
import modelController.viewerController.MainXhtml;
import org.apache.poi.sl.usermodel.TableCell;
import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xslf.usermodel.XSLFTable;
import org.apache.poi.xslf.usermodel.XSLFTableCell;
import org.apache.poi.xslf.usermodel.XSLFTableRow;
import org.apache.poi.xslf.usermodel.XSLFTextBox;
import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
import org.apache.poi.xslf.usermodel.XSLFTextRun;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.jsoup.select.Elements;
import sessionBeans.KnowledgeFacadeLocal;
import tools.StaticFields;
import java.net.URLEncoder;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Named("knowledgeController")
@SessionScoped

/**
 * @author haogs 郝国生，许梦楠（生成PPT）
 */
public class KnowledgeController extends CommonModelController<Knowledge> implements Serializable {

    @Inject
    private SubjectController subjectController;
    @Inject
    private MajorController majorController;
    @Inject
    private SchoolController schoolController;
    @Inject
    private LearningresourceController learningresourceController;
    @Inject
    private modelController.applicationController.EdgeamongknowledgeController applicationEdgeamongknowledgeController;
    @Inject
    private modelController.applicationController.ReexaminationController applicationReexaminationController;
    @Inject
    private modelController.applicationController.KnowledgeController applicationKnowledgeController;
    @Inject
    private modelController.applicationController.RoleinfoController applicationRoleinfoController;
    @Inject
    private modelController.applicationController.LearningresourceController applicationLearningresourceController;
    @Inject
    private modelController.applicationController.StatusofresourcesController applicationStatusofresourcesController;
    @Inject
    private modelController.applicationController.PraiseController applicationPraiseController;
    @Inject
    private modelController.applicationController.LeadpointController applicationLeadpointController;
    @Inject
    private tools.UserMessagor userMessagor;
    @Inject
    private modelController.sessionController.CommonSession commonSession;
    @Inject
    private EdgeamongknowledgeController edgeamongknowledgeController;
    @Inject
    private MainXhtml mainXhtml;
    @Inject
    private modelController.applicationController.StudentController applicationStudentController;
    @Inject
    private modelController.sessionController.ReexaminationController reexaminationController;
    @Inject
    private modelController.sessionController.MyPublishedKnowledgeController myPublishedKnowledgeController;
    @Inject
    private modelController.applicationController.SubjectController applicationSubjectController;
    @EJB
    private KnowledgeFacadeLocal knowledgeFacadeLocal;
    private boolean isChanged = false;//判断是否进行修改,如果是修改，则不判重复与否
    private String searchName = "";
    private final String tableName = "knowledge",
            listpage = "knowledge/List",
            editpage = "knowledge/CreateSecondStep",
            viewpage = "knowledge/View",
            pptPage = "knowledge/CreatePPT",
            knowledgeRegulization = "knowledge/KnowledgeRegulization";
    protected final String createpage = "knowledge/Create";
    private Map<Integer, Knowledge> knowledgesInMemeory = new HashMap<>();

    private void initKnowledgesInMemeory() {
        //8846是布鲁姆认知的6层次理论
        knowledgesInMemeory.put(8846, this.getKnowledge(8846));
    }

    public KnowledgeController() {
    }
    protected Knowledge current;

    public Knowledge getSelected() {
        if (current == null) {
            selectedItemIndex = -1;
            current = new Knowledge();
        }
        return current;
    }

    //@PostConstruct
    //这里使用subjectController.getSelected(),而在subjectController.getSelected()则使用knowledgeController.getSelected构成了循环死循环调用了
    public void setDataModelList() {
        if (null != subjectController.getSelected().getId()) {
            pageOperation.setDataModelList(applicationKnowledgeController.getKnowledgeList4Subject(subjectController.getSelected()));
        }
    }

    //-------------------------------For the search and viewall command button------------------
    //Have an int to check whether the subject is changed, if not, omit the execution of the SQL
    // private int selectedSubjectId = 0;
    //当课程发生改变后，就要按课程获取上一个知识点，如果未发生改变，就按照本知识点求取课程，再求取上一个知识点
    public List<Knowledge> getKnowledgeList4Subject(int type, Knowledge knowledge) {
        List<Knowledge> temKnowledges;
        //如果知识点不为空，则一定可以获得其对应的课程，从而获得知识点列表
        if (null != knowledge && null != knowledge.getId()) {
            temKnowledges = applicationKnowledgeController.getKnowledgeList4Subject(knowledge.getSubjectId());
            if (type == 0) {//说明是要从中选择其父类知识点，所以要删除自身
                temKnowledges.remove(knowledge);
            }
        } else {//优先知识点，没有则直接从subject中取就可以了
            temKnowledges = applicationKnowledgeController.getKnowledgeList4Subject(subjectController.getSelected());
        }
        return temKnowledges;
    }

    public List<Knowledge> getKnowledgeList4Subject() {
        return getKnowledgeList4Subject(1, null);
    }

    public void prepareMyRecorderKnowledgeList(Integer status) {
        User user = null;
        switch (commonSession.getUserType()) {
            case Student:
                user = studentController.getLogined();
                break;
            case Teacher:
            case Reexamin:
                user = teacherAdminController.getLogined();
                break;
            case Parent:
                user = parentController.getLogined();
                break;
        }
        List<Knowledge> result = getMyRecorderKnowledgeList(user, status);
        pageOperation.refreshData(result);
        if (result.size() > 0) {
            setSelected(result.get(0));
        }
    }

    private List<Knowledge> getMyRecorderKnowledgeList(User user, Integer status) {
        StringBuilder sb = new StringBuilder();
        if (null != user && null != user.getId()) {
            List<Reexamination> reexaminations = reexaminationController.getReexaminationKnowledgeListRecorderBy(user, status);
            reexaminations.forEach(re -> {
                sb.append(re.getKnowledgeid().getId()).append(",");
            });
        }
        String ids = sb.toString();
        if (ids.length() > 0) {
            ids = ids.endsWith(",") ? ids.substring(0, ids.length() - 1) : ids;
            return knowledgeFacadeLocal.getQueryResultList("select * from knowledge where id in (" + ids + ")");
        } else {
            return new LinkedList<>();
        }
    }

    public void prepareMyExaminedKnowledgeList(Integer status, Integer secondStatus) {
        TeacherAdmin user = teacherAdminController.getLogined();
        List<Knowledge> result = null;
        StringBuilder sb = new StringBuilder();
        List<Reexamination> reexaminations = reexaminationController.getReexaminationNeedToBeExamined(user, status, 0, secondStatus);
        reexaminations.forEach(re -> {
            sb.append(re.getKnowledgeid().getId()).append(",");
        });
        String ids = sb.toString();
        if (ids.length() > 0) {
            ids = ids.endsWith(",") ? ids.substring(0, ids.length() - 1) : ids;
            result = knowledgeFacadeLocal.getQueryResultList("select * from knowledge where id in (" + ids + ")");
        } else {
            result = new LinkedList<>();
        }
        pageOperation.refreshData(result);
        if (result.size() > 0) {
            setSelected(result.get(0));
        }
    }

    public void search() {
        if (searchName.trim().length() > 0) {
            List<Knowledge> searchedResult;
            if (subjectController.getSelected().getId() != null) {
                searchedResult = applicationKnowledgeController.searchByString(searchName, subjectController.getSelected().getId());
            } else {
                searchedResult = applicationKnowledgeController.searchByString(searchName, 0);
            }
            this.logs(searchName, tableName, StaticFields.OPERATIONSEARCH);
            pageOperation.refreshData(searchedResult);
            if (searchedResult.size() > 0) {
                setSelected(searchedResult.get(0));
                userMessagor.addMessage(commonSession.getResourceBound().getString("Succeed"));
            } else {
                userMessagor.addMessage(commonSession.getResourceBound().getString("Failed"));
            }
        } else {
            userMessagor.addMessage(commonSession.getResourceBound().getString("Please") + " "
                    + commonSession.getResourceBound().getString("Specify") + " "
                    + commonSession.getResourceBound().getString("Whatyouwanttosearch")
            );
        }
    }

    public String getSearchName() {
        return searchName;
    }

    public void setSearchName(String searchName) {
        this.searchName = searchName.toLowerCase();
    }

    public boolean canDelete() {
        return null == edgeamongknowledgeSet ? true : edgeamongknowledgeSet.isEmpty();
    }

    public String showedName(Knowledge knowledge) {
        StringBuilder sb = new StringBuilder();
        User tem;
        if (null != knowledge) {
            Set<Reexamination> reexaminations = applicationReexaminationController.getReexamination4Knowledge(knowledge);
            if (!reexaminations.isEmpty()) {
                Reexamination reexamination = (Reexamination) reexaminations.toArray()[0];
                tem = reexamination.getTeacherid();
                if (null == tem) {//不是教师
                    tem = reexamination.getStudentid();
                    if (null == tem) {//不是学生
                        tem = reexamination.getParentid();
                    }
                }
                if (null != tem) {//也可能为空
                    sb.append(null == tem.getSecondname() ? "" : tem.getSecondname()).append(" ")
                            .append(null == tem.getFirstname() ? "" : tem.getFirstname());
                }
            }
        }
        return sb.toString();
    }

    public void setSelected(Knowledge current) {
        this.current = current;
        //更新内存变量temporaryEdgeamongknowledges，这里保存了本体的SPO
        if (null != temporaryEdgeamongknowledges) {
            temporaryEdgeamongknowledges.clear();
        } else {
            temporaryEdgeamongknowledges = new HashSet<>();
        }
        if (null != current && null != current.getSuccessorknowledgeSet()) {
            temporaryEdgeamongknowledges.addAll(current.getPredcessorKnowledgeSet());
        }
        //这个重置知识点间关系
        resetRelation();
    }

    public String resetSelected(Knowledge current) {
        this.current = current;
        return null;
    }
    private List<Knowledge> selectedmany;
    private HashMap<Subject, HashMap<Integer, Knowledge>> subjectKnowledges = new HashMap<>();//在这里把application中的knowledge拿来，放在这儿，selectedMay从这里直接检索，避免到数据库中检查

    public HashMap<Integer, Knowledge> getSubjectKnowledges(Subject subject) {
        if (null == subjectKnowledges.get(subject)) {
            List<Knowledge> knowledges = applicationKnowledgeController.getKnowledgeList4Subject(subject);
            HashMap<Integer, Knowledge> temMap = new HashMap<>();
            for (Knowledge knowledge : knowledges) {
                temMap.put(knowledge.getId(), knowledge);
            }
            subjectKnowledges.put(subject, temMap);
        }
        return subjectKnowledges.get(subject);
    }

    public List<Knowledge> getSelectedMany() {
        if (null == selectedmany) {
            selectedmany = new LinkedList<>();
        }
        return selectedmany;
    }

    List<Knowledge> currKnowledgesList;

    public void setSelectedMany(List<Integer> myKnowledges) {
        if (myKnowledges.size() > 0) {
            selectedmany = new LinkedList<>();
            HashMap<Integer, Knowledge> knowledgeList = getSubjectKnowledges(subjectController.getSelected());
            for (int i = 0; i < myKnowledges.size(); i++) {
                selectedmany.add(knowledgeList.get(myKnowledges.get(i)));
            }
        }
    }
//------------------prepare View, edit, list,create------------------

    public String prepareList() {
        if (fromPublished) {
            myPublishedKnowledgeController.prepareList();
            fromPublished = false;
        } else {
            pageOperation.refreshData(new ArrayList(subjectController.getSelected().getKnowledgeSet()));
            setSelected(subjectController.getSelected().getStartKnowledge());
        }
        mainXhtml.setPageName(this.listpage);
        return null;
    }

    public void prepareView() {
        if (!fromCreate) {
            if (null != getItems()) {
                setSelected((Knowledge) (getItems().getRowData()));
            }
        }
        if (!fromPublished) {
            selectedItemIndex = pageOperation.getPagination().getPageFirstItem() + getItems().getRowIndex();
        }
        mainXhtml.setPageName(this.viewpage);
    }

    public void prepareView(Knowledge knowledge) {
        refreshKnowledges();//For the Edit viewer, where the selected and candidated subjects
        setSelected(knowledge);
        selectedItemIndex = pageOperation.getPagination().getPageFirstItem() + getItems().getRowIndex();
        mainXhtml.setPageName(this.viewpage);
        setTemSelectedLeft(null);
    }

    public void prepareView(int id) {
        refreshKnowledges();//For the Edit viewer, where the selected and candidated subjects
        setSelected(applicationKnowledgeController.getKnowledge(id));
        selectedItemIndex = pageOperation.getPagination().getPageFirstItem() + getItems().getRowIndex();
        mainXhtml.setPageName(this.viewpage);
        setTemSelectedLeft(null);
    }

    public void prepareCreate() {
        refreshKnowledges();//当选定课程后，就可以显示知识点关系图了，以便在创建、编辑过程中查看与使用
        setSelected(new Knowledge());
        selectedItemIndex = -1;
        mainXhtml.setPageName(this.createpage);
        isChanged = false;
    }

    public void finishAddEdge() {
        mainXhtml.setPageName(this.viewpage);
    }
    boolean fromCreate = false;

    public void create() {
        //检查知识点的name和detail是否具有了值
        learningresourceController.setIs4knowledge(true);//
        try {
            //1. check whether the name existed? If true, deny the operation;else continue;
            if (isChanged
                    ||//正在修改，而不是新建，所以不用判断是否已经存在
                    !applicationKnowledgeController.isKnowledgeExisted(current.getName(), subjectController.getSelected())) {
                //不用esle，因为调用这里的不仅有新建，而且还有修改也需要走这里
                refreshKnowledges();//For the Edit viewer, where the selected and candidated subjects
                current.setSubjectId(subjectController.getSelected());
                this.logs(current.getName(), tableName, StaticFields.OPERATIONINSERT);
                if (isChanged) {//正在修改，而不是新建
                    applicationKnowledgeController.edit(current);
                } else {
                    applicationKnowledgeController.create(current);
                    //current.setDetails(this.dealWithInnerKnowledgeIndex(current.getDetails()));
                    reexaminationController.createReexamination(current, null);
                    //setOldKnowledge();
                }
                userMessagor.addMessage(commonSession.getResourceBound().getString("Succeed"));
                //2. Refresh the data
                pageOperation.refreshData(applicationKnowledgeController.getKnowledgeList4Subject(subjectController.getSelected()));
                fromCreate = true;
                setTemSelectedLeft(null);
                mainXhtml.setPageName(this.editpage);
                similarKnowledges.clear();//把相似的知识点列表清空，以便于下一次新建时用于判断
                resetIndex();
            } else {
                userMessagor.addMessage(commonSession.getResourceBound().getString("Already") + " " + commonSession.getResourceBound().getString("Exist"));
            }
        } catch (Exception e) {
            System.out.println("KnowledgeController create erro");
        }

    }

    public void prepareEdit() {
        if (!fromPublished) {//从“发布的知识点”页面来
            setSelected((Knowledge) getItems().getRowData());
            this.refreshKnowledges();
            if (subjectController.isSelectedNull()) {
                subjectController.setSelected(getSelected().getSubjectId());
            }
            if (majorController.isSelectedNull()) {
                Set<Majorsubject> majorset = subjectController.getSelected().getMajorsubjectSet();
                for (Majorsubject majorsubject : majorset) {
                    majorController.setSelected(majorsubject.getMajorid());
                    break;
                }
            }
        }
        selectedItemIndex = pageOperation.getPagination().getPageFirstItem() + getItems().getRowIndex();
        isChanged = true;
        mainXhtml.setPageName(this.createpage);
        temSelectedLeft = null;
    }

    public void gotoView() {
        mainXhtml.setPageName(this.viewpage);
    }

    public String edit() {
        isChanged = true;
        mainXhtml.setPageName(this.createpage);
        this.refreshKnowledges();
        temSelectedLeft = null;
        resetIndex();
        return null;
    }

    public void refreshKnowledges() {
        getPageOperation().refreshData();
    }

    public void submit4Reexamination() {//提交审核
        Set<Reexamination> reexaminations = applicationReexaminationController.getReexamination4Knowledge(current);
        if (!reexaminations.isEmpty()) {
            Reexamination tem = (Reexamination) reexaminations.toArray()[0];
            tem.setStatus(applicationStatusofresourcesController.getStatusofresources(0));
            applicationReexaminationController.edit(tem);
            mainXhtml.setPageName(this.listpage);//当跳转到带svg的页面时总是出错，目前还不知道原因
        }
    }

    private void saveBefore() {
        if (null == current.getSubjectId() || null == current.getSubjectId().getId() //|| !(subjectController.getSelected().getId().equals(current.getSubjectId().getId()))
                ) {
            current.setSubjectId(subjectController.getSelected());
        }
        applicationKnowledgeController.edit(current);
        resetRelation();//刷新边
        this.refreshKnowledges();//For the Edit viewer, where the selected and candidated subjects
    }

    private void saveAfter() {
        try {
            if (applicationRoleinfoController.isSecreatary(teacherAdminController.getLogined())) {
                //The secretary adjust the knowledgeId
                getSelected().setSubjectId(subjectController.getSelected());
                refreshKnowledges();
            }
            //applicationKnowledgeController.edit(getSelected());
            //getPageOperation().recreateModel();
            //evictForeignKey();
            userMessagor.addMessage(commonSession.getResourceBound().getString("Succeed"));
            mainXhtml.setPageName(this.viewpage);
            this.logs(current.getName(), tableName, StaticFields.OPERATIONUPDATE);
        } catch (Exception e) {
            userMessagor.addMessage(commonSession.getResourceBound().getString("Failed") + "Controller Knowledge 2");
            mainXhtml.setPageName(this.viewpage);
        }
    }

    public void saveNow() {//update for edgeAmongKnowledge
        saveBefore();
        Set<Reexamination> reexaminations = applicationReexaminationController.getReexamination4Knowledge(current);
        if (!reexaminations.isEmpty()) {
            Reexamination tem = (Reexamination) reexaminations.toArray()[0];
            tem.setStatus(applicationStatusofresourcesController.getStatusofresources(3));
            applicationReexaminationController.edit(tem);
        }
        saveAfter();
    }

    public void saveAnd2EdgeamongKnowledge() {
        saveNow();
        edgeamongknowledgeController.prepareCreate();
    }

    public void destroy() {
        current = (Knowledge) getItems().getRowData();
        selectedItemIndex = pageOperation.getPagination().getPageFirstItem() + getItems().getRowIndex();
        performDestroy();
        subjectController.getSelected().getKnowledgeSet().remove(current);
        setSelected(null);//为了让系统可以重新去获得Subject，以便重新画图
        mainXhtml.setPageName(this.listpage);
        setTemSelectedLeft(null);
        resetIndex();
    }
    int index = 1;

    public String getIndex() {
        return "k" + (++index);
    }

    private void resetIndex() {
        this.index = 1;//重置List.xhmtl中用到的index
    }

    public String getSameIndex() {
        return "k" + index;
    }

    private void performDestroy() {
        try {
            if (current.getQuestionSet().isEmpty()) {
                removeKnowledge();
            } else {
                userMessagor.addMessage(commonSession.getResourceBound().getString("Exist") + " "
                        + commonSession.getResourceBound().getString("Question"));
            }
            //evictForeignKey();
            userMessagor.addMessage(commonSession.getResourceBound().getString("Succeed"));
            updateCurrentItem();
            //knowledgesList.remove(current);
            getPageOperation().recreateModel();;
            pageOperation.refreshData(applicationKnowledgeController.getKnowledgeList4Subject(subjectController.getSelected()));
            this.logs(current.getName(), tableName, StaticFields.OPERATIONDELETE);
        } catch (Exception e) {
            userMessagor.addMessage(commonSession.getResourceBound().getString("Failed") + "Controller Knowledge 3");
        }
    }

    private void removeKnowledge() {
        Set<Reexamination> setOfReexaminations = current.getReexaminationSet();
        for (Reexamination reexamination : setOfReexaminations) {
            applicationReexaminationController.remove(reexamination);
        }
        Set<Learningresource> setOfLearningresources = current.getLearningresourceSet();
        for (Learningresource learningresource : setOfLearningresources) {
            applicationLearningresourceController.remove(learningresource);
        }
        Set<Edgeamongknowledge> setOfEdgeamongknowledges = current.getPredcessorKnowledgeSet();
        for (Edgeamongknowledge edgeamongknowledge : setOfEdgeamongknowledges) {
            applicationEdgeamongknowledgeController.remove(edgeamongknowledge);
        }
        setOfEdgeamongknowledges = current.getSuccessorknowledgeSet();
        for (Edgeamongknowledge edgeamongknowledge : setOfEdgeamongknowledges) {
            applicationEdgeamongknowledgeController.remove(edgeamongknowledge);
        }
        Set<Praise> setOfPraises = current.getPraiseSet();
        for (Praise praise : setOfPraises) {
            applicationPraiseController.remove(praise);
        }

        applicationKnowledgeController.remove(current);
    }

    private void updateCurrentItem() {
        int count = applicationKnowledgeController.count();
        if (selectedItemIndex >= count) {
            // selected index cannot be bigger than number of items:
            selectedItemIndex = count - 1;
            // go to previous page if last page disappeared:
            pageOperation.refreshData();
            if (pageOperation.getPagination().getPageFirstItem() >= count) {
                pageOperation.getPagination().previousPage();
            }
        }
        if (selectedItemIndex >= 0) {
            setSelected((Knowledge) applicationKnowledgeController.findRange(new int[]{selectedItemIndex, selectedItemIndex + 1}).get(0));
        }
    }

    @Override
    public DataModel getItems() {
        if (null != subjectController.getSelected().getId() && subjectController.isRenewed()) {
            pageOperation.refreshData(applicationKnowledgeController.getKnowledgeList4Subject(subjectController.getSelected()));
        }
        return pageOperation.getItems();
    }

    public Knowledge getKnowledge(java.lang.Integer id) {
        return (Knowledge) applicationKnowledgeController.find(id);
    }

    //-------------------------------
    //================For the parents knowledge ===============
    //temKnowledges is those being selected in the manyListbox
    private HashSet<Knowledge> temSelectedLeft = new HashSet<>(), temSelectedRight = new HashSet<>(),
            temSelectedLeftNew = new HashSet<>();//用来临时存在保存的值

    public Set<Knowledge> getTemSelectedLeft() {
        temSelectedLeft = applicationKnowledgeController.getPredcessorKnowledges(getSelected());
        return temSelectedLeft;
    }

    public void setTemSelectedLeft(HashSet<Knowledge> subjectList) {
        temSelectedLeft = subjectList;
        if (null != subjectList) {
            temSelectedLeftNew.clear();
            temSelectedLeftNew.addAll(temSelectedLeft);
        }
    }

    public HashSet<Knowledge> getTemSelectedLeftNew() {
        return temSelectedLeftNew;
    }

    public Set<Knowledge> getTemSelectedRight() {
        return temSelectedRight;
    }

    public void setTemSelectedRight(HashSet<Knowledge> subjectList) {
        temSelectedRight = subjectList;
    }
//   //================For the parents knowledge ===============
//    //temKnowledges is those being selected in the manyListbox
//    private HashSet<Predicate> temSelectedLeftPredicates = new HashSet<>();//用来临时存在保存的值
//
//    public HashSet<Predicate> getTemSelectedLeftPredicates() {
//        return temSelectedLeftPredicates;
//    }
//
//    public void setTemSelectedLeftPredicates(HashSet<Predicate> temSelectedLeftPredicates) {
//        this.temSelectedLeftPredicates = temSelectedLeftPredicates;
//    }
    private Part knowledgeExcelFile;

    public Part getKnowledgeExcelFile() {
        return knowledgeExcelFile;
    }

    public void setKnowledgeExcelFile(Part knowledgeExcelFile) {
        this.knowledgeExcelFile = knowledgeExcelFile;
    }

    public String knowledgesUpload() {
        List<NewOldID> newoldIds = new ArrayList<>();
        int i = 2;
        try {
            if (null == subjectController.getSelected().getId()) {
                userMessagor.addMessage(commonSession.getResourceBound().getString("Select") + commonSession.getResourceBound().getString("Subject"));
                return null;
            }
            if (null == this.knowledgeExcelFile || this.getFilename(knowledgeExcelFile).trim().length() == 0) {
                userMessagor.addMessage(commonSession.getResourceBound().getString("ExcelSelection"));
                return null;
            }
            InputStream ins = knowledgeExcelFile.getInputStream();
            Workbook book = Workbook.getWorkbook(ins);
            Sheet sheet = book.getSheet(0);
            int rownum = sheet.getRows();
            try {
                for (; i < rownum; i++) {
                    Knowledge knowledge = new Knowledge();
                    Edgeamongknowledge edgeamongknowledge = new Edgeamongknowledge();
                    //存储到数据库后产生的新的knowledge对象
                    Knowledge createdNewId = null;
                    //判断数据库是否存在sheet当前行的知识点名称，如果没有则写入
                    if (applicationKnowledgeController.getQueryResultList("select * from knowledge where name='" + sheet.getCell(2, i).getContents().trim() + "' and subject_id=" + subjectController.getSelected().getId()).isEmpty()) {
                        knowledge.setSubjectId(subjectController.getSelected());
                        knowledge.setName(sheet.getCell(2, i).getContents());
                        knowledge.setDetails(sheet.getCell(3, i).getContents());
//                            knowledge.setLevelnumber();
                        applicationKnowledgeController.create(knowledge);
                        reexaminationController.createReexamination(knowledge, null);
                    }
                    List<Knowledge> knowledges = applicationKnowledgeController.getQueryResultList("select * from knowledge where name='" + sheet.getCell(2, i).getContents().trim() + "' and subject_id=" + subjectController.getSelected().getId());
                    //拿到当前行新的知识点id值
                    createdNewId = (Knowledge) knowledges.get(0);
//                    newoldIdMap.put(createdNewId.getId(), Integer.parseInt(sheet.getCell(0, i).getContents()));
                    Integer preNode = null;
                    //第一个知识点前驱为null，判断当前前驱是否能成功转成数字
                    try {
                        preNode = Integer.parseInt(sheet.getCell(1, i).getContents());
                    } catch (Exception e) {
                        //第一次写到map里面，如果之后前驱转换有错则不写入
                        newoldIds.add(new NewOldID(createdNewId.getId(), Integer.parseInt(sheet.getCell(0, i).getContents())));
                        System.out.println("第一次写到map里面，如果之后前驱转换有错则不写入");
                    }
                    //如果成功转换，则遍历map找到此知识点的前驱和map中存储的旧的id值是否相同
                    if (preNode != null) {
                        for (NewOldID newOldID : newoldIds) {
                            if (Objects.equals(newOldID.oldId, preNode)) {
                                //如果相同，则把当前知识点的id和当前知识点前驱对应的新的id放到前驱后继关系表里面
                                edgeamongknowledge.setSuccessornode(createdNewId);
                                edgeamongknowledge.setPredecessornode(new Knowledge(newOldID.newId));
                                //判断数据库里面是否已经存在此关系，如果没有则写入
                                if (applicationEdgeamongknowledgeController.getQueryResultList("select * from EDGEAMONGKNOWLEDGE where successornode=" + edgeamongknowledge.getSuccessornode().getId() + " and predecessornode=" + edgeamongknowledge.getPredecessornode().getId()).isEmpty()) {
                                    applicationEdgeamongknowledgeController.create(edgeamongknowledge);
                                }
                                break;
                            }
                        }
                        //当遍历完map之后再存储新的id值和旧的id值到map里面
                        newoldIds.add(new NewOldID(createdNewId.getId(), Integer.parseInt(sheet.getCell(0, i).getContents())));
                    }

                }
            } catch (NumberFormatException e) {
                System.out.println("数值转换异常");
                i = -1;
            } finally {
                book.close();
            }
//            }
        } catch (BiffException | IOException ex) {
            System.out.println("赋值-2");
            i = -2;
        }

        switch (i) {
            case -2:
                userMessagor.addMessage(commonSession.getResourceBound().getString("ExcelWrong3"));
            case -1:
                userMessagor.addMessage(current.getName() + ":" + commonSession.getResourceBound().getString("ExcelWrong2"));
                break;
            case 2:
                userMessagor.addMessage(commonSession.getResourceBound().getString("Import") + commonSession.getResourceBound().getString("Empty"));
                break;
            default:
                userMessagor.addMessage(commonSession.getResourceBound().getString("Succeed") + " " + i + commonSession.getResourceBound().getString("Knowledge"));
        }
        return null;
    }

    private String getFilename(Part part) {
        for (String cd : part.getHeader("content-disposition").split(";")) {
            if (cd.trim().startsWith("filename")) {
                String filename = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
                return filename.substring(filename.lastIndexOf('/') + 1).substring(filename.lastIndexOf('\\') + 1); // MSIE fix.
            }
        }

        return null;
    }

    public String getKnowledgeRelationship4dagre() {
        String result = "";
        Knowledge knowledge = null;
        if (getSelected().getId() == null) {//一开始，没有知识点被选中
            if (subjectController.getSelected().getId() != null) {//如果课程已经被选中了，那么就执行下面的
                if (subjectController.getSelected().getStartKnowledge() != null) {
                    knowledge = subjectController.getSelected().getStartKnowledge();
                } else {
                    Knowledge startKnowledge = new Knowledge();
                    startKnowledge.setSubjectId(subjectController.getSelected());
                    startKnowledge.setName(subjectController.getSelected().getName() + "Start");
                    applicationKnowledgeController.create(startKnowledge);
                    subjectController.getSelected().setStartKnowledge(startKnowledge);
                    applicationSubjectController.edit(subjectController.getSelected());
                    knowledge = startKnowledge;
                }
            } else {
                userMessagor.addMessage(commonSession.getResourceBound().getString("No")
                        + commonSession.getResourceBound().getString("Knowledge")
                        + commonSession.getResourceBound().getString("And")
                        + commonSession.getResourceBound().getString("Subject")
                        + commonSession.getResourceBound().getString("Select")
                );
                return null;
            }
        } else {
            knowledge = getSelected();
        }
        result = applicationKnowledgeController.getKnowledgeRelationship4dagre(knowledge);
        //System.out.println(result);
        return result;
    }

    public void setKnowledgeRelationship4dagre(String virtualString) {//Just a virtual one, but not a real one
    }

    public String getAllStudentKnowledge() {
        if (null == schoolController.getSelected().getId()) {
            return "";
        } else {
            Set<Student> studentSet = new HashSet<>();
            if (null == studentController.getSelected().getId()) {
                List<Student> students = applicationStudentController.getStudentList(schoolController.getSelected());
                studentSet.addAll(students);
            } else {
                studentSet.add(studentController.getSelected());
            }
            String result = "digraph {"
                    + "node [rx=5 ry=5 labelStyle=\"font: 300 14px 'Helvetica Neue', Helvetica\"] "
                    + "edge [labelStyle=\"font: 300 14px 'Helvetica Neue', Helvetica\"]";

            return result + getKnowledgeRelationship4dagre(subjectController.getSelected(), studentSet) + "}";
        }

    }

    Set<Knowledge> getKnowledgeToRecursion(Knowledge k) {
        Set<Knowledge> knowledgeSet = new HashSet<>();
        //递归结束条件
        //如果传入的知识点为空，返回null
        if (k == null) {
            return null;
        }
        //k不为空，放入当前知识点
        knowledgeSet.add(k);
        if (k.getSuccessorknowledgeSet() == null) {
            //后继为空，写入当前知识点集合
            return knowledgeSet;
        }
        for (Edgeamongknowledge eak : k.getSuccessorknowledgeSet()) {
            k = eak.getSuccessornode();
            knowledgeSet.add(k);
            knowledgeSet.addAll(getKnowledgeToRecursion(k));
        }
        return knowledgeSet;
    }

    private void renameDuplicate(String name) {
        List<Knowledge> knoweList = applicationKnowledgeController.getQueryResultList("select * from knowledge where name='" + name.trim() + "'");
        knoweList.forEach(knowledge -> {
            knowledge.setName(knowledge.getSubjectId().getName() + knowledge.getName());
            applicationKnowledgeController.edit(knowledge);
        });
    }

    public String renameStartAndEnd() {
        this.renameDuplicate("start");
        this.renameDuplicate("end");
        userMessagor.addMessage(commonSession.getResourceBound().getString("Succeed"));
        return null;
    }

    //下面处理学习资源：图像、音频和视频
    //boolean learningResourceChanged = true;
    private List<Learningresource> learningresourcesList = new LinkedList<>();

    private void resourceClear(int type) {
        if (type == StaticFields.AUDIOTYPE) {
            audioLearningresources.clear();
        }
        if (type == StaticFields.VIDEOTYPE) {
            videoLearningresources.clear();
        }
        if (type == StaticFields.IMAGETYPE) {
            imageLearningresources.clear();
        }
        if (type == StaticFields.PDFTYPE) {
            pdfLearningResource.clear();
        }
    }

    public List<Learningresource> getLearningResource(int type, Knowledge knowledge) {
        String sqlString = "";
        if (knowledge.getId() == null || null == knowledge) {
            sqlString = "select * from learningresource where type=" + type;
        } else if (knowledge.getId() != null) {
            sqlString = "select * from learningresource where knowledge_id=" + knowledge.getId() + " and type=" + type;
        }
        learningresourcesList = applicationLearningresourceController.getQueryResultList(sqlString);
        resourceClear(type);
        learningresourcesList.forEach(resource -> {
            if (type == StaticFields.IMAGETYPE && resource.getType() == StaticFields.IMAGETYPE) {
                imageLearningresources.add(resource);
            }
            if (type == StaticFields.VIDEOTYPE && resource.getType() == StaticFields.VIDEOTYPE) {
                videoLearningresources.add(resource);
            }
            if (type == StaticFields.AUDIOTYPE && resource.getType() == StaticFields.AUDIOTYPE) {
                audioLearningresources.add(resource);
            }
            if (type == StaticFields.PDFTYPE && resource.getType() == StaticFields.PDFTYPE) {
                pdfLearningResource.add(resource);
            }
        });
        //learningResourceChanged = false;

        return learningresourcesList;
    }
    private List<Learningresource> imageLearningresources = new LinkedList<>(),
            videoLearningresources = new LinkedList<>(),
            audioLearningresources = new LinkedList<>(), pdfLearningResource = new LinkedList<>();

    public List<Learningresource> getImageResource(Knowledge knowledge) {
        getLearningResource(StaticFields.IMAGETYPE, knowledge);
        return imageLearningresources;
    }

    public List<Learningresource> getVedioResource(Knowledge knowledge) {
        getLearningResource(StaticFields.VIDEOTYPE, knowledge);
        return videoLearningresources;
    }

    public List<Learningresource> getAudioResource(Knowledge knowledge) {
        getLearningResource(StaticFields.AUDIOTYPE, knowledge);
        return audioLearningresources;
    }

    public List<Learningresource> getPDFResource(Knowledge knowledge) {
        getLearningResource(StaticFields.PDFTYPE, knowledge);
        return pdfLearningResource;
    }

    public List<String> getResourceString(List<Learningresource> resourceList) {
        List<String> fileNames = new LinkedList<>();
        resourceList.forEach(resource -> {
            String[] names = resource.getValueinfo().split(",");
            fileNames.addAll(Arrays.asList(names));
        });
        return fileNames;
    }

    //==================重复检测===============开始========
    List<Knowledge> similarKnowledges = new LinkedList<>();

    public List<Knowledge> getSimilarKnowledges() {
        int type = 0;
        if (null != current.getName() && current.getName().trim().length() > 0) {//如果正在查知识点名称
            type = 1;
        }
        //如果知识点细节也完善了，默认名称已经通过了，查细节部分
        if (null != current.getDetails() && current.getDetails().trim().length() > 13) {//因为可能只包含<p>&nbsp;</p>这个富文本
            type = 2;
        }
        if (type > 0) {
            similarKnowledges = applicationKnowledgeController.getSimilarKnowledges(current.getName(), type);
        }
        return similarKnowledges;
    }

    public boolean showSimilarKnowledge() {
        return similarKnowledges.size() > 0;
    }

    //==================重复检测===============结束========
    private class NewOldID {

        private Integer newId;
        private Integer oldId;

        public NewOldID() {
        }

        public NewOldID(Integer newId, Integer oldId) {
            this.newId = newId;
            this.oldId = oldId;
        }

        public Integer getNewId() {
            return newId;
        }

        public void setNewId(Integer newId) {
            this.newId = newId;
        }

        public Integer getOldId() {
            return oldId;
        }

        public void setOldId(Integer oldId) {
            this.oldId = oldId;
        }

    }

//下面处理知识点关联关系
    //下面这个内部类用于记录当前用户的操作，如删除或新增知识点间关系，当持久化操作时把对应的这些记录写入到数据库中
    private Set<Edgeamongknowledge> temporaryEdgeamongknowledges;//存储临时新增或删除的知识点关系，在保存时再持久化到数据库中
    //保存temporaryEdgeamongknowledges中的三元组信息
    HashMap<Integer, Edgeamongknowledge> edgeamongknowledgeSet;

    private int id = 0;//记录在knowledg--CreateSecondStep中知识点关系SPO中O对应的知识点，如果在删除情况下，这选中的是要删除的关系

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    private void resetRelation() {
        edgeamongknowledgeSet = null;
        temporaryEdgeamongknowledges = null;
        id = 0;
    }

    public HashMap<Integer, Edgeamongknowledge> getTemporaryEdgeamongknowledgesMap() {
        if (null == edgeamongknowledgeSet || edgeamongknowledgeSet.isEmpty()) {
            edgeamongknowledgeSet = new HashMap<>();
            //int id = 0;
            for (Edgeamongknowledge ek : getTemporaryEdgeamongknowledges()) {
                edgeamongknowledgeSet.put(id++, ek);
            }
        }
        return edgeamongknowledgeSet;
    }

    public Edgeamongknowledge getEdgeamongknowledge() {
        return edgeamongknowledgeSet.get(id);
    }

    private Set<Edgeamongknowledge> getTemporaryEdgeamongknowledges() {
        if (null == temporaryEdgeamongknowledges) {
            temporaryEdgeamongknowledges = new HashSet<>();
            temporaryEdgeamongknowledges.addAll(applicationEdgeamongknowledgeController.getByPredecessor(getSelected()));
        }
        return temporaryEdgeamongknowledges;
    }

    public HashMap<Integer, String> getLevelMap() {
        
        HashMap<Integer,String> levelMap=applicationKnowledgeController.getLevelMap();
//        HashMap<Integer,String> result=new HashMap<>();
//        for (Entry entry: levelMap.entrySet()) {
//            if((Integer)entry.getKey()>=current.getLevelnumber()){
//                result.put((Integer)entry.getKey(), (String)entry.getValue());
//            }
//        }
        return levelMap;
    }

    private HashMap<Integer, String> knowledgeTypeMap = null;

    public HashMap<Integer, String> getKnowledgeTypeMap() {
        if (null == knowledgeTypeMap) {
            knowledgeTypeMap = new HashMap<>();
            knowledgeTypeMap.put(1, commonSession.getResourceBound().getString("K1nowledgeType"));
            knowledgeTypeMap.put(2, commonSession.getResourceBound().getString("K2nowledgeType"));
            knowledgeTypeMap.put(3, commonSession.getResourceBound().getString("K3nowledgeType"));
            knowledgeTypeMap.put(4, commonSession.getResourceBound().getString("K4nowledgeType"));
        }
        return knowledgeTypeMap;
    }
    private boolean fromPublished = false;
    //在prepareList中设置回false

    //从myPublishedKnowledge来调用Edit和View页面
    public boolean isFromPublished() {
        return fromPublished;
    }

    public boolean isSelectedNull() {
        return null == current || null == getSelected().getId();
    }

    public void setFromPublished(boolean fromPublished) {
        this.fromPublished = fromPublished;
    }
//        public boolean canAdd() {
//        return relatedKnolwdge == null || relatedKnolwdge.getId() == null
//                || predicateController.getSelected() == null || predicateController.getSelected().getId() == null;
//    }

    //    public void addKnowledgeRelation() {//对应于添加按钮
//        if (null == predicateController.getSelected() || null == relatedKnolwdge) {//没有选择
//            return;
//        }
//        Edgeamongknowledge temEdgeamongknowledge = new Edgeamongknowledge();
//        temEdgeamongknowledge.setPredecessornode(relatedKnolwdge);
//        temEdgeamongknowledge.setSuccessornode(this.getSelected());
//        temEdgeamongknowledge.setPredicate(predicateController.getSelected());
//        int temId = getTemporaryEdgeamongknowledgesMap().keySet().size();
//        while (getTemporaryEdgeamongknowledgesMap().keySet().contains(temId)) {
//            temId++;
//        }
//        getTemporaryEdgeamongknowledgesMap().put(temId, temEdgeamongknowledge);
//    }
    public String getKnowledgeRelationship4dagre4OneStudent() {
        return getKnowledgeRelationship4dagre4OneStudent(subjectController.getSelected(), studentController.getSelected());
    }

    public String getKnowledgeRelationship4dagre4OneStudent(Subject subject, Student student) {
        String result = "digraph {"
                + "node [rx=5 ry=5 labelStyle=\"font: 300 14px 'Helvetica Neue', Helvetica\"] "
                + "edge [labelStyle=\"font: 300 14px 'Helvetica Neue', Helvetica\"]";
        if (subject == null || subject.getId() == null) {
            result += "}";
        } else {
            HashSet<Student> oneStudent = new HashSet<>();
            oneStudent.add(student);
            result += getKnowledgeRelationship4dagre(subject, oneStudent) + "}";
        }
        return result;
    }

    private String getKnowledgeRelationship4dagre(Subject subject, Set<Student> studentSet) {
        List<Knowledge> leadingPoint = new LinkedList<>();
        if (studentSet.size() > 0) {
            for (Student student : studentSet) {
                //拿到学生所有的知识点前沿
//                List<Leadpoint> leadpoints = applicationLeadpointController.getAllLeadpointList(student, subject);
//                for (Leadpoint leadpoint : leadpoints) {
//                    leadingPoint.addAll(getKnowledgesList4LeadingPoint(leadpoint));
//                }
                //现在改为拿到学生最新的知识点前沿
                List<Leadpoint> leadpoints = applicationLeadpointController.getAllLeadpointList(student, subject);
                if (!leadpoints.isEmpty()) {
                    leadingPoint.addAll(applicationKnowledgeController.getKnowledgesList4LeadingPoint(leadpoints.get(0)));
                }

            }
        }
        String resultString = "";
        //Color those knowledge on the leading point
        if (leadingPoint.size() > 0 && studentSet.size() > 1) {
            Map<Knowledge, Integer> knowledgeCount = new HashMap<Knowledge, Integer>();
            Set<Knowledge> leadingPointSet = new HashSet<>(leadingPoint);
            for (Knowledge k : leadingPointSet) {
                knowledgeCount.put(k, 1);
            }
            for (Knowledge current : leadingPoint) {
                for (Map.Entry<Knowledge, Integer> entry : knowledgeCount.entrySet()) {
                    if (Objects.equals(current.getId(), entry.getKey().getId())) {;
                        entry.setValue(entry.getValue() + 1);
                        break;
                    }

                }
            }
            for (Map.Entry<Knowledge, Integer> entry : knowledgeCount.entrySet()) {
                int kCount = entry.getValue();
                //double fontSize = 32 + Math.ceil(kCount * 0.6);
                double colorRed = 1 + Math.ceil(kCount * 9);
                if (colorRed > 255) {
                    colorRed = 255;
                }
                int colorIndex = (int) Math.ceil(colorRed / 25.5) - 1;
//                String colorStr = "rgb(" + colorRed + ",0,0)";
                resultString += "\"" + entry.getKey().getName()
                        + "\" [labelType=\"html\" label=\"<span style='font-size:"
                        + applicationKnowledgeController.getFontSizeArr()[colorIndex] + "px;color:"
                        + applicationKnowledgeController.getColorStrArr()[colorIndex] + ";'>" + entry.getKey().getName()
                        + "</span>\"];";

            }
            setLeadpointInformation(commonSession.getResourceBound().getString("Leadpoint")
                    + ":" + leadingPoint.size()
            );
        } else {
            for (Knowledge current : leadingPoint) {
                resultString += "\"" + current.getName()
                        + "\" [labelType=\"html\" label=\"<span style='font-size:32px;color:red;'>" + current.getName()
                        + "</span>\"];";
            }
            setLeadpointInformation(commonSession.getResourceBound().getString("No")
                    + commonSession.getResourceBound().getString("Leadpoint")
            );
        }
        List<Edgeamongknowledge> tem = applicationEdgeamongknowledgeController.getEdgeamongknowledgeList(subject);
        for (Edgeamongknowledge edge : tem) {
            resultString += applicationEdgeamongknowledgeController.getString4Dagre(edge);
        }
        return resultString;
    }

    private String leadpointInformation = "";

    public String getLeadpointInformation() {
        return subjectController.getSubjectName() + leadpointInformation;
    }

    public void setLeadpointInformation(String leadpointInformation) {
        this.leadpointInformation = leadpointInformation;
    }

    public Knowledge getKnowledgesInMemeory(int id) {
        if (knowledgesInMemeory.isEmpty()) {
            initKnowledgesInMemeory();
        }
        Knowledge result = knowledgesInMemeory.get(id);
        if (result == null) {
            result = this.getKnowledge(id);
        }
        return result;
    }

    public String getKeyKnowledge4SchoolSubject() {
        List<Student> Students = applicationStudentController.getStudent4School(schoolController.getSelected());
        Subject suject = subjectController.getSelected();
        List<Knowledge> leadingPoint = new LinkedList<>();
        Map<Knowledge, Integer> knowledgeCount = new HashMap<>();
        if (!Students.isEmpty()) {
            for (Student temp : Students) {
                List<Leadpoint> leadpoints = applicationLeadpointController.getAllLeadpointList(temp, suject);
                if (!leadpoints.isEmpty()) {
                    leadingPoint.addAll(applicationKnowledgeController.getKnowledgesList4LeadingPoint(leadpoints.get(0)));
                }
            }

            if (!leadingPoint.isEmpty() && Students.size() > 1) {
                for (Knowledge k : leadingPoint) {
                    if (knowledgeCount.containsKey(k)) {
                        knowledgeCount.put(k, knowledgeCount.get(k) + 1);
                    } else {
                        knowledgeCount.put(k, 1);
                    }
                }
            } else {
                return null;
            }
        } else {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<Knowledge, Integer> entry : knowledgeCount.entrySet()) {
            sb.append(",")
                    .append(entry.getKey().getName())
                    .append(entry.getValue());
        }
        return sb.toString();
    }

    //    创建知识点PPT
    public String toPPT() {
        mainXhtml.setPageName(pptPage);
        return null;
    }

    /*
**使用的log4j是2.17，2.20出错
     */
    public String createPPT() throws IOException {
        XMLSlideShow ppt = new XMLSlideShow();
        List<Knowledge> pptKnowledges = getSelectedMany();
        //把knowledge按照依赖关系重新排序
        repaireRelationSship(pptKnowledges);
        //
        for (Knowledge knowledge : pptKnowledges) {
            makePPT(ppt, knowledge);
        }
        //       ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        //       ppt.write(byteArrayOutputStream);
        //       byte[] pptBytes = byteArrayOutputStream.toByteArray();
        HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
        //response.setContentType("application/octet-stream");
        // 设置响应的头部信息，包括文件名和内容长度  
        //response.setContentLength(pptBytes.length);
        response.setContentType("application/vnd.openxmlformats-officedocument.presentationml.presentation");
//        response.setHeader("Content-Disposition", "attachment; filename=" + subjectController.getSelected().getName() + ".ppt");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(subjectController.getSelected().getName() + ".pptx", "UTF-8"));

        OutputStream out = null;
        try {
            out = response.getOutputStream();
            try (BufferedOutputStream bos = new BufferedOutputStream(out)) {
                ppt.write(bos);
            }
            out.flush();
        } catch (IOException ex) {
            Logger.getLogger(KnowledgeController.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("knowledgeController--createPPT");
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(KnowledgeController.class.getName()).log(Level.SEVERE, null, ex);
                System.out.println("knowledgeController--createPPT");
            }
        }
        return null;
    }
    //参考https://poi.apache.org/components/slideshow/xslf-cookbook.html

    private void makePPT(XMLSlideShow ppt, Knowledge knowledge) {
        String subjectName = knowledge.getSubjectId().getName();
        String details = knowledge.getDetails();
        String knowledgeName = knowledge.getName();
        String levelNumber = knowledge.getLevelnumber().toString();
        //添加空白幻灯片
        XSLFSlide slide = ppt.createSlide();
        //获取幻灯片的尺寸
        Dimension pageSize = ppt.getPageSize();
        //幻灯片添加文本框
        addTextBox(slide, subjectName, 0, 0, (int) pageSize.getWidth(), 40, "right", new Color(255, 255, 255));
        addTextBox(slide, knowledgeName, 0, 40, (int) pageSize.getWidth(), 40, "left", new Color(115, 148, 175));
//        addTextBox(slide, details, 0, 80, (int) pageSize.getWidth(), (int) pageSize.getHeight() - 120, "JUSTIFY", new Color(193, 193, 156));
        //具体内容部分处理
        dealKnowledgeDetails(ppt, slide, details);
        addTextBox(slide, levelNumber, 0, (int) pageSize.getHeight() - 40, (int) pageSize.getWidth(), 40, "left", new Color(115, 148, 175));
    }

    // 封装创建文本框的方法
    private void addTextBox(XSLFSlide slide, String text, int x, int y, int width, int height, String location, Color color) {
        XSLFTextBox textBox = slide.createTextBox();
        XSLFTextParagraph paragraph = textBox.addNewTextParagraph();
        XSLFTextRun textRun = paragraph.addNewTextRun();
        textBox.setAnchor(new java.awt.Rectangle(x, y, width, height));
        textBox.setFillColor(color);
        textRun.setText(text);
        textRun.setFontFamily("Times New Roman");
        switch (location) {
            case "right":
                paragraph.setTextAlign(TextParagraph.TextAlign.RIGHT);
                break;
            case "left":
                paragraph.setTextAlign(TextParagraph.TextAlign.LEFT);
                break;
            default:
                paragraph.setTextAlign(TextParagraph.TextAlign.JUSTIFY);
        }
        // 设置文本样式
        textRun.setFontSize(14.0);
        textRun.setBold(true);
        textRun.setFontColor(Color.BLACK);
    }

    private void dealKnowledgeDetails(XMLSlideShow ppt, XSLFSlide slide, String details) {
        if (null == details || details.isEmpty() || details.equalsIgnoreCase("<p>&nbsp;</p>") || details.equalsIgnoreCase("无") || details.equalsIgnoreCase("")) {
            XSLFTextBox textBox = slide.createTextBox();
            textBox.setAnchor(new Rectangle(0, 80, (int) ppt.getPageSize().getWidth(), (int) ppt.getPageSize().getHeight() - 120));
            XSLFTextParagraph paragraph = textBox.addNewTextParagraph();
            XSLFTextRun textRun = paragraph.addNewTextRun();
            textRun.setText("暂无数据");
            textRun.setFontSize(14.0);
        } else {
            if (containsHtmlTag(details)) {
                //字符串包含HTML标签
                convertHtmlToPPT(details, slide, ppt);
            } else {
                //字符串不包含html标签
                XSLFTextBox textBox = slide.createTextBox();
                textBox.setAnchor(new Rectangle(0, 80, (int) ppt.getPageSize().getWidth(), (int) ppt.getPageSize().getHeight() - 120));
                XSLFTextParagraph paragraph = textBox.addNewTextParagraph();
                XSLFTextRun textRun = paragraph.addNewTextRun();
                textRun.setText(details);
                textRun.setFontSize(14.0);
            }
        }
    }

    private boolean containsHtmlTag(String input) {
        // 使用正则表达式检查字符串中是否包含 HTML 标签
        String htmlTagPattern = "<[^>]+>";
        Pattern pattern = Pattern.compile(htmlTagPattern);
        Matcher matcher = pattern.matcher(input);
        return matcher.find();
    }

    private void convertHtmlToPPT(String details, XSLFSlide slide, XMLSlideShow ppt) {
        Document doc = Jsoup.parse(details);
        //判断是否是表格
        boolean hasTable = containHtmlTable(doc);
        if (hasTable == false) {
            //无表格
            converParagraphToPPT(doc, slide, ppt);
        } else {
            HTMLTableToPPT(doc, slide, ppt);
        }
    }

    //   判断html是否包含表格标签
    private static boolean containHtmlTable(Document document) {
        Elements tables = document.select("table");
        return !tables.isEmpty();
    }

    //无表格的富文本处理
    private void converParagraphToPPT(Document doc, XSLFSlide slide, XMLSlideShow ppt) {
        XSLFTextBox textBox = slide.createTextBox();
        StringBuilder sentenceBuilder = new StringBuilder();
        //判断是否含p标签
        //不包含p标签，只有其他块级标签
        if (doc.select("p").size() == 0) {
            XSLFTextRun textRun = textBox.addNewTextParagraph().addNewTextRun();
            textRun.setFontSize(14.0);
            if (!doc.select("h1").isEmpty()) {
                sentenceBuilder.append(doc.select("h1").text() + "\n");
                textRun.setFontSize(18.0);
            }
            if (!doc.select("h2").isEmpty()) {
                sentenceBuilder.append(doc.select("h2").text() + "\n");
                textRun.setFontSize(16.0);
            }
            if (!doc.select("h3").isEmpty()) {
                sentenceBuilder.append(doc.select("h3").text() + "\n");
                textRun.setFontSize(14.0);
            }
            if (!doc.select("ol").isEmpty()) {
                int index = 1;
                Elements listElement = doc.select("li");
                System.out.println(listElement);
                for (Element element : listElement) {
                    sentenceBuilder.append(index + ":" + element.text() + "\n");
                    index++;
                }
            }
            if (!doc.select("ul").isEmpty()) {
                Elements listElement = doc.select("li");
                for (Element element : listElement) {
                    sentenceBuilder.append(element.text() + "\n");
                }
            }
            textRun.setText(sentenceBuilder.toString());
        } else {
            //p标签
            parseHTMLAndInsert(doc, textBox);
        }
        textBox.setAnchor(new Rectangle(0, 80, (int) ppt.getPageSize().getWidth(), (int) ppt.getPageSize().getHeight() - 120));
    }

    private void HTMLTableToPPT(Document doc, XSLFSlide slide, XMLSlideShow ppt) {
        boolean hasTabHeader = hasTableHeader(doc);
        List<Integer> rowAndCol = countRowsAndCols(doc);
        Elements rows = doc.select("tr");
        XSLFTable table = slide.createTable(rowAndCol.get(0), rowAndCol.get(1));
        table.setAnchor(new java.awt.Rectangle(0, 80, (int) ppt.getPageSize().getWidth(), (int) ppt.getPageSize().getHeight() - 120));
        setBorderColorAndWidth(rowAndCol, table);
        if (!hasTabHeader) {
            //无表头
            int rowIndex = 0;
            int colIndex = 0;
            int beforeMerge = 0;
            for (Element row : rows) {
                Elements tds = row.select("td");
                for (Element td : tds) {
                    if (td.attr("rowspan").isEmpty()) {
                        boolean flag = table.getCell(rowIndex, colIndex).getText().isEmpty();
                        if (flag == true) {
                            XSLFTextParagraph paragraph = table.getCell(rowIndex, colIndex).addNewTextParagraph();
                            XSLFTextRun textRun = paragraph.addNewTextRun();
                            textRun.setFontSize(12.0);
                            textRun.setText(td.text());
                        } else {
                            for (int col = colIndex; col <= rowAndCol.get(1); col++) {
                                if (table.getCell(rowIndex, col).getText().isEmpty()) {
                                    XSLFTextRun textRun = table.getCell(rowIndex, col).addNewTextParagraph().addNewTextRun();
                                    textRun.setFontSize(12.0);
                                    textRun.setText(td.text());
                                    break;
                                }
                            }
                        }
                    } else {
                        String rowspan = td.attr("rowspan");
                        int mergeNumber = Integer.parseInt(rowspan);
                        beforeMerge = beforeMerge + mergeNumber;
                        int i = rowIndex;
                        for (i = rowIndex; i < rowIndex + mergeNumber; i++) {
                            XSLFTextRun textRun = table.getCell(i, colIndex).addNewTextParagraph().addNewTextRun();
                            textRun.setFontSize(12.0);
                            textRun.setText(td.text());
                        }
                        table.mergeCells(rowIndex, rowIndex + mergeNumber - 1, colIndex, colIndex);
                    }
                    colIndex++;
                }
                rowIndex++;
                colIndex = 0;
            }
        } else {
            //有表头
            StringBuilder sentenceBuilder = null;
            for (int rowIndex = 0; rowIndex < rowAndCol.get(0); rowIndex++) {
                Element row = rows.get(rowIndex);
                XSLFTableRow tableRow = table.getRows().get(rowIndex);
                for (int colIndex = 0; colIndex < rowAndCol.get(1); colIndex++) {
                    Element cellElement = row.child(colIndex);
                    XSLFTableCell tableCell = tableRow.getCells().get(colIndex);
                    XSLFTextParagraph p = tableCell.addNewTextParagraph();
                    XSLFTextRun textRun = p.addNewTextRun();
                    String cellText = cellElement.html();
                    if (cellText.contains("<br>")) {
                        cellText = cellText.replaceAll("<br>", "\n");
                    }
                    if (cellText.contains("&nbsp;")) {
                        cellText = cellText.replaceAll("&nbsp;", "").trim();
                    }
                    if (!containsHtmlTag(cellText)) {
                        textRun.setFontSize(5.0);
                        textRun.setText(cellText);
                    } else {
                        sentenceBuilder = new StringBuilder();
                        if (!cellElement.select("p").isEmpty()) {
                            sentenceBuilder.append(cellElement.select("p").text() + "\n");
                        }
                        if (!cellElement.select("ul").isEmpty()) {
                            Elements listElement = cellElement.select("li");
                            for (Element element : listElement) {
                                sentenceBuilder.append("·" + element.text() + "\n");
                            }
                        }
                        if (!cellElement.select("ol").isEmpty()) {
                            int index = 1;
                            Elements listElement = cellElement.select("li");
                            for (Element element : listElement) {
                                sentenceBuilder.append(index + ":" + element.text() + "\n");
                                index++;
                            }
                        }
                        if (!cellElement.select("span").isEmpty()) {
                            sentenceBuilder.append(cellElement.select("span").text() + "\n");
                        }
                        if (sentenceBuilder.length() == 0) {
                            textRun.setText("000000");
                        } else {
                            textRun.setFontSize(5.0);
                            textRun.setText(sentenceBuilder.toString().trim());
                        }
                    }
                }
            }
        }
        //判断是否还含有table之外的其他标签
        int tableNum = doc.select("table").size();
        int divNum = doc.select("table,p,h1,h2,h3,ol,ul,li").not("table p,table ul,table ol,table li,table h1,table h2,table h3").size();
        if (divNum > tableNum) {
            Elements elements = doc.select("table,p,h1,h2,h3,ol,ul,li").not("table p,table ul,table ol,table li,table h1,table h2,table h3").not("table");
            XSLFTextBox textBox = slide.createTextBox();
            textBox.setAnchor(new Rectangle(50, 300, (int) ppt.getPageSize().getWidth(), (int) ppt.getPageSize().getHeight() - 300));
            XSLFTextParagraph paragraph = textBox.addNewTextParagraph();
            for (Element element : elements) {
                for (Node node : element.childNodes()) {
                    if (node instanceof TextNode) {
                        XSLFTextRun run = paragraph.addNewTextRun();
                        run.setText(((TextNode) node).text());
                        run.setFontSize(8.0);
                    } else if (node instanceof Element) {
                        process_html(node, paragraph);
                    }
                }
                paragraph.addNewTextRun().setText("\n");
            }
        }
    }

    // 检查表格是否有表头
    private boolean hasTableHeader(Document document) {
        Elements tables = document.select("table");
        for (Element table : tables) {
            // 找到第一个<tr>元素
            Element firstRow = table.selectFirst("tr");
            if (firstRow != null) {
                // 检查第一行是否包含<th>元素
                Elements headerCells = firstRow.select("th");
                if (!headerCells.isEmpty()) {
                    return true;
                }
            }
        }
        return false;
    }

    private static java.util.List countRowsAndCols(Document document) {
        List<Integer> countList = new ArrayList<>();
        Elements table = document.select("table");
        for (Element ta : table) {
            int rowCount = 0;
            int colCount = 0;
            Elements rows = table.select("tr");
            rowCount = rows.size();
            countList.add(rowCount);
            for (Element row : rows) {
                Elements cols = row.select("td, th");
                if (cols.size() > colCount) {
                    colCount = cols.size();
                }
            }
            countList.add(colCount);
        }
        return countList;
    }

    //    设置单元格边框格式
    private static void setBorderColorAndWidth(List<Integer> totalCount, XSLFTable table) {
        for (int i = 0; i < totalCount.get(0); i++) {
            for (int j = 0; j < totalCount.get(1); j++) {
                table.getCell(i, j).setBorderColor(TableCell.BorderEdge.left, Color.BLACK);
                table.getCell(i, j).setBorderColor(TableCell.BorderEdge.top, Color.BLACK);
                table.getCell(i, j).setBorderColor(TableCell.BorderEdge.right, Color.BLACK);
                table.getCell(i, j).setBorderColor(TableCell.BorderEdge.bottom, Color.BLACK);
                table.getCell(i, j).setBorderWidth(TableCell.BorderEdge.left, 1.0);
                table.getCell(i, j).setBorderWidth(TableCell.BorderEdge.top, 1.0);
                table.getCell(i, j).setBorderWidth(TableCell.BorderEdge.right, 1.0);
                table.getCell(i, j).setBorderWidth(TableCell.BorderEdge.bottom, 1.0);
            }
        }
    }

    private void parseHTMLAndInsert(Document doc, XSLFTextBox textBox) {
        Element body = doc.body();
        Elements tags = body.select("p, h3, ul, ol");
        for (Element tag : tags) {
            XSLFTextParagraph paragraph = textBox.addNewTextParagraph();
            for (Node node : tag.childNodes()) {
                if (node instanceof TextNode) {
                    XSLFTextRun run = paragraph.addNewTextRun();
                    run.setText(((TextNode) node).text());
                } else if (node instanceof Element) {
                    process_html(node, paragraph);
                }
            }
        }
    }

    private void process_html(Node node, XSLFTextParagraph paragraph) {
        // 定义正则表达式匹配HTML标签的模式
        String pattern = "<[^>]*>";
        // 创建Pattern对象
        Pattern tagPattern = Pattern.compile(pattern);
        // 创建Matcher对象
        Matcher tagMatcher = tagPattern.matcher(node.toString());
        // 使用正则表达式将HTML标签替换为空字符串
        String textWithoutTags = tagMatcher.replaceAll("");
        XSLFTextRun run = paragraph.addNewTextRun();
        run.setText(textWithoutTags);
        run.setFontSize(8.0);
        // 设置不同的文本段格式，例如粗体和斜体
        if (node.nodeName().equalsIgnoreCase("b") || node.nodeName().equalsIgnoreCase("strong")) {
            run.setBold(true);
        } else if (node.nodeName().equalsIgnoreCase("i")) {
            run.setItalic(true);
        } else if (node.nodeName().equalsIgnoreCase("br")) {
            run.setText("\n");
        } else if (node.nodeName().equalsIgnoreCase("a")) {
            run.setUnderlined(true);
        }
    }

    public String toKnowledgeRegulization() {
        mainXhtml.setPageName(knowledgeRegulization);
        applicationSubjectController.repaireKnowledgeRelation();
        return null;
    }

    private void repaireRelationSship(List<Knowledge> pptKnowledges) {
        //将knowledge按照遍历顺序排列，从而使得输出的PPT的逻辑合理
        if (pptKnowledges.size() > 0) {
            List<Knowledge> sortedKnowledges = applicationKnowledgeController.getSortedKnowledges(pptKnowledges.get(0).getSubjectId());
            Map<Knowledge, Integer> orderMap = new HashMap<>();
            for (int i = 0; i < sortedKnowledges.size(); i++) {
                orderMap.put(sortedKnowledges.get(i), i);
            }
            pptKnowledges.sort(Comparator.comparingInt(s -> Optional.ofNullable(orderMap.get(s)).orElse(Integer.MAX_VALUE)));
        }
    }

}
